using ChatGPT.Net;
using ChatGpt_WebApp.ApiDto;
using ChatGpt_WebApp.ThirdApi;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Extensions;
using Newtonsoft.Json.Linq;
using NLog;

namespace ChatGpt_WebApp.Controllers;


[ApiController]
[Route("api/[controller]/[action]")]
[DisableCors]
public partial class ChatApiController : ControllerBase
{   
    //对话ID映射，因为部分ID违规后会被封禁，所以不能直接使用原始ID
    static Dictionary<string,string> conversationIdMap = new Dictionary<string, string>();

    readonly IChatApi chatApi;
    readonly IHostEnvironment env;
    readonly ILogger<ChatApiController> logger;

    public ChatApiController(IChatApi chatApi, IHostEnvironment env, ILogger<ChatApiController> logger)
    {
        this.chatApi = chatApi;
        this.env = env;
        this.logger = logger;
    }
    
    private string GetConversationId(int cid){
        var conversationId = HttpContext.Connection.RemoteIpAddress!.ToString() + "_" + cid;        
        if(!conversationIdMap.ContainsKey(conversationId)){
            conversationIdMap.Add(conversationId, conversationId+"_"+DateTime.Now.Ticks);
        }
        var result = conversationIdMap[conversationId];
        return result;
    }
    
    private int GetOrCreateTokenId()
    {
        var tokenIdStr = this.HttpContext.Request.Cookies["tokenid"];

        var createToken = new Func<int>(() =>
        {
            var token = TokenManager.GetToken(1);
            this.HttpContext.Response.Cookies.Delete("tokenid");
            this.HttpContext.Response.Cookies.Append("tokenid", token.TokenId.ToString(), new CookieOptions()
            {
                Expires = DateTime.Now.AddHours(3),
            });
            return token.TokenId;
        });

        int tokenId;
        if (!int.TryParse(tokenIdStr, out tokenId))
        {
            tokenId = createToken();
        }
        else
        {
            var findToken = TokenManager.GetToken(tokenId);
            if (findToken == null || findToken.Expired)
            {
                tokenId = createToken();
            }
        }

        return tokenId;
    }

    private int? GetTokenId()
    {
        var tokenId = this.HttpContext.Request.Cookies["tokenid"];
        if (tokenId == null) return null;
        return int.Parse(tokenId);
    }

    //根据性格模型组合问题
    private string CombineQuestion(string question, int cid)
    {
        var character = GetCharacter(cid);
        var aiDesc = string.Format(AppSetting.Current!.ChatGpt!.Character!.Template!, character.AiDesc);
        if (cid == 0) aiDesc = "";
        question = aiDesc + question;
        return question;
    }

    //获取性格模型
    private CharacterInfo GetCharacter(int id)
    {
        var list = AppSetting.Current!.ChatGpt.Character!.Characters;

        var find = list.FirstOrDefault(f => f.Id == id);
        if (find == null) return CharacterInfo.Default;

        return find;
    }
    
    /// <summary>
    /// 清除对话
    /// </summary>
    /// <param name="cid"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<ApiResult> ResetConversation(int cid = 0)
    {
        var conversationId = GetConversationId(cid);        
        await chatApi.ResetConversation(conversationId);
        conversationIdMap.Remove(HttpContext.Connection.RemoteIpAddress!.ToString() + "_" + cid);
        return ApiResult.SuccessResult;
    }

    /// <summary>
    /// 获取Ai基本数据
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public ApiResult GetChatContext()
    {
        var gpt = AppSetting.Current!.ChatGpt!;
        var list = gpt.Character!.Characters;

        var dto = new ChatAiDto();
        dto.AiName = gpt.AiName!;
        dto.MaxQuesionLength = gpt.MaxQuesionLength;
        dto.Version = gpt.Version!;
        if (!list.Any()) list.Add(CharacterInfo.Default);
        foreach (var item in list)
        {
            dto.Characters.Add(new CharacterDto()
            {
                Id = item.Id!,
                Name = string.Format(item.Name!, gpt.AiName),
                Desc = string.Format(item.Desc!, gpt.AiName),
                Icon = item.Icon!,
                HeadSrc = item.HeadSrc!,
                WelcomeFromAi = item.WelcomeFromAi,
                WelcomeMsgList = item.WelcomeMsgList!,
                ReConversationMsgList = item.ReConversationMsgList!
            });
        }

        return new ApiResult(dto);
    }

    /// <summary>
    /// 向ChatGpt提问
    /// </summary>
    /// <param name="question">问题内容</param>
    /// <param name="cid">性格模型id</param>
    /// <returns></returns>
    [HttpGet]
    public async Task<ApiResult> Ask(string question, int cid = 0)
    {
        var dto = new ApiResult();
        var ip = HttpContext.Connection.RemoteIpAddress!.ToString();
        var setting = AppSetting.Current.ChatGpt;
        var logChat = !setting.LogIps!.Any() || setting!.LogIps!.Any(a => a == ip);
        var ei = new LogEventInfo(NLog.LogLevel.Trace, "chatLogger", string.Format(ip + " 提出问题: {0}", question));

        ei.Properties["ip"] = ip.Replace(":ffff:", "").Replace("f", "").Replace(":", "");
        var chatLogger = LogManager.GetLogger("chatLogger");
        if (logChat) chatLogger.Log(ei);

        //如果是官方API,则可以详细配置
        if(chatApi is OfficialChatGptApi){
             var character = GetCharacter(cid);
            var officialChatApi = chatApi as OfficialChatGptApi;
            officialChatApi!.BotSetting(setting=>{
                setting.Temperature = character.Temperature;                
            });
        }

        question = CombineQuestion(question,cid);
        
        var result = await chatApi.Ask(question, GetConversationId(cid));
        dto.Data = result.Content;
        dto.Success = result.Success;


        ei.Message = string.Format("AI回答: {0}", dto.Data);
        if (logChat) chatLogger.Log(ei);

        if (env.IsDevelopment())
        {
            if (result.Exception != null)
            {
                dto.Data = string.Format(@"出现异常:```txt {0} ```", result.Exception.Message);
                logger.LogError(result.Exception, "回答异常");
            }
        }
        return await Task.FromResult(dto);
    }




    /// <summary>
    /// 向我问好
    /// </summary>
    /// <param name="cid"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<ApiResult> SayHello(int cid)
    {
        var dto = new ApiResult();
        var quesion = "用你的性格向我打个招呼，像是认识的人见面一样，不要太过死板，不要强调自己的性格";

        var result = await chatApi.Ask(CombineQuestion(quesion,cid), GetConversationId(cid));
        dto.Success = result.Success;
        dto.Data = result.Content;

        return dto;
    }


}